home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _9AB4F6BC67C14F0D90D398C89A719EDF < prev    next >
Encoding:
Text File  |  2002-07-01  |  23.4 KB  |  1,381 lines

  1. // Copyright (C) 2001-2002 Raven Software.
  2. //
  3. // q_shared.c -- stateless support routines that are included in each code dll
  4. #include "q_shared.h"
  5.  
  6.  
  7. /*
  8. -------------------------
  9. GetIDForString 
  10. -------------------------
  11. */
  12.  
  13.  
  14. int GetIDForString ( stringID_table_t *table, const char *string )
  15. {
  16.     int    index = 0;
  17.  
  18.     while ( ( table[index].name != NULL ) &&
  19.             ( table[index].name[0] != 0 ) )
  20.     {
  21.         if ( !Q_stricmp( table[index].name, string ) )
  22.             return table[index].id;
  23.  
  24.         index++;
  25.     }
  26.  
  27.     return -1;
  28. }
  29.  
  30. /*
  31. -------------------------
  32. GetStringForID
  33. -------------------------
  34. */
  35.  
  36. const char *GetStringForID( stringID_table_t *table, int id )
  37. {
  38.     int    index = 0;
  39.  
  40.     while ( ( table[index].name != NULL ) &&
  41.             ( table[index].name[0] != 0 ) )
  42.     {
  43.         if ( table[index].id == id )
  44.             return table[index].name;
  45.  
  46.         index++;
  47.     }
  48.  
  49.     return NULL;
  50. }
  51.  
  52. float Com_Clampf( float min, float max, float value ) 
  53. {
  54.     if ( value < min ) 
  55.     {
  56.         return min;
  57.     }
  58.     if ( value > max ) 
  59.     {
  60.         return max;
  61.     }
  62.     return value;
  63. }
  64.  
  65. int Com_Clamp( int min, int max, int value ) 
  66. {
  67.     if ( value < min ) 
  68.     {
  69.         return min;
  70.     }
  71.     if ( value > max ) 
  72.     {
  73.         return max;
  74.     }
  75.     return value;
  76. }
  77.  
  78.  
  79. /*
  80. ============
  81. COM_SkipPath
  82. ============
  83. */
  84. char *COM_SkipPath (char *pathname)
  85. {
  86.     char    *last;
  87.     
  88.     last = pathname;
  89.     while (*pathname)
  90.     {
  91.         if (*pathname=='/')
  92.             last = pathname+1;
  93.         pathname++;
  94.     }
  95.     return last;
  96. }
  97.  
  98. /*
  99. ============
  100. COM_StripExtension
  101. ============
  102. */
  103. void COM_StripExtension( const char *in, char *out ) {
  104.     while ( *in && *in != '.' ) {
  105.         *out++ = *in++;
  106.     }
  107.     *out = 0;
  108. }
  109.  
  110.  
  111. /*
  112. ==================
  113. COM_DefaultExtension
  114. ==================
  115. */
  116. void COM_DefaultExtension (char *path, int maxSize, const char *extension ) {
  117.     char    oldPath[MAX_OSPATH];
  118.     char    *src;
  119.  
  120. //
  121. // if path doesn't have a .EXT, append extension
  122. // (extension should include the .)
  123. //
  124.     src = path + strlen(path) - 1;
  125.  
  126.     while (*src != '/' && src != path) {
  127.         if ( *src == '.' ) {
  128.             return;                 // it has an extension
  129.         }
  130.         src--;
  131.     }
  132.  
  133.     Q_strncpyz( oldPath, path, sizeof( oldPath ) );
  134.     Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
  135. }
  136.  
  137. /*
  138. ============================================================================
  139.  
  140.                     BYTE ORDER FUNCTIONS
  141.  
  142. ============================================================================
  143. */
  144. /*
  145. // can't just use function pointers, or dll linkage can
  146. // mess up when qcommon is included in multiple places
  147. static short    (*_BigShort) (short l);
  148. static short    (*_LittleShort) (short l);
  149. static int        (*_BigLong) (int l);
  150. static int        (*_LittleLong) (int l);
  151. static qint64    (*_BigLong64) (qint64 l);
  152. static qint64    (*_LittleLong64) (qint64 l);
  153. static float    (*_BigFloat) (const float *l);
  154. static float    (*_LittleFloat) (const float *l);
  155.  
  156. short    BigShort(short l){return _BigShort(l);}
  157. short    LittleShort(short l) {return _LittleShort(l);}
  158. int        BigLong (int l) {return _BigLong(l);}
  159. int        LittleLong (int l) {return _LittleLong(l);}
  160. qint64     BigLong64 (qint64 l) {return _BigLong64(l);}
  161. qint64     LittleLong64 (qint64 l) {return _LittleLong64(l);}
  162. float    BigFloat (const float *l) {return _BigFloat(l);}
  163. float    LittleFloat (const float *l) {return _LittleFloat(l);}
  164. */
  165.  
  166. short   ShortSwap (short l)
  167. {
  168.     byte    b1,b2;
  169.  
  170.     b1 = l&255;
  171.     b2 = (l>>8)&255;
  172.  
  173.     return (b1<<8) + b2;
  174. }
  175.  
  176. short    ShortNoSwap (short l)
  177. {
  178.     return l;
  179. }
  180.  
  181. int    LongSwap (int l)
  182. {
  183.     byte    b1,b2,b3,b4;
  184.  
  185.     b1 = l&255;
  186.     b2 = (l>>8)&255;
  187.     b3 = (l>>16)&255;
  188.     b4 = (l>>24)&255;
  189.  
  190.     return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
  191. }
  192.  
  193. int    LongNoSwap (int l)
  194. {
  195.     return l;
  196. }
  197.  
  198. qint64 Long64Swap (qint64 ll)
  199. {
  200.     qint64    result;
  201.  
  202.     result.b0 = ll.b7;
  203.     result.b1 = ll.b6;
  204.     result.b2 = ll.b5;
  205.     result.b3 = ll.b4;
  206.     result.b4 = ll.b3;
  207.     result.b5 = ll.b2;
  208.     result.b6 = ll.b1;
  209.     result.b7 = ll.b0;
  210.  
  211.     return result;
  212. }
  213.  
  214. qint64 Long64NoSwap (qint64 ll)
  215. {
  216.     return ll;
  217. }
  218.  
  219. typedef union {
  220.     float    f;
  221.     unsigned int i;
  222. } _FloatByteUnion;
  223.  
  224. float FloatSwap (const float *f) {
  225.     const _FloatByteUnion *in;
  226.     _FloatByteUnion out;
  227.  
  228.     in = (_FloatByteUnion *)f;
  229.     out.i = LongSwap(in->i);
  230.  
  231.     return out.f;
  232. }
  233.  
  234. float FloatNoSwap (const float *f)
  235. {
  236.     return *f;
  237. }
  238.  
  239. /*
  240. ================
  241. Swap_Init
  242. ================
  243. */
  244. /*
  245. void Swap_Init (void)
  246. {
  247.     byte    swaptest[2] = {1,0};
  248.  
  249. // set the byte swapping variables in a portable manner    
  250.     if ( *(short *)swaptest == 1)
  251.     {
  252.         _BigShort = ShortSwap;
  253.         _LittleShort = ShortNoSwap;
  254.         _BigLong = LongSwap;
  255.         _LittleLong = LongNoSwap;
  256.         _BigLong64 = Long64Swap;
  257.         _LittleLong64 = Long64NoSwap;
  258.         _BigFloat = FloatSwap;
  259.         _LittleFloat = FloatNoSwap;
  260.     }
  261.     else
  262.     {
  263.         _BigShort = ShortNoSwap;
  264.         _LittleShort = ShortSwap;
  265.         _BigLong = LongNoSwap;
  266.         _LittleLong = LongSwap;
  267.         _BigLong64 = Long64NoSwap;
  268.         _LittleLong64 = Long64Swap;
  269.         _BigFloat = FloatNoSwap;
  270.         _LittleFloat = FloatSwap;
  271.     }
  272.  
  273. }
  274. */
  275.  
  276. /*
  277. ============================================================================
  278.  
  279. PARSING
  280.  
  281. ============================================================================
  282. */
  283.  
  284. static    char    com_token[MAX_TOKEN_CHARS];
  285. static    char    com_parsename[MAX_TOKEN_CHARS];
  286. static    int        com_lines;
  287.  
  288. void COM_BeginParseSession( const char *name )
  289. {
  290.     com_lines = 0;
  291.     Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
  292. }
  293.  
  294. int COM_GetCurrentParseLine( void )
  295. {
  296.     return com_lines;
  297. }
  298.  
  299. char *COM_Parse( const char **data_p )
  300. {
  301.     return COM_ParseExt( data_p, qtrue );
  302. }
  303.  
  304. void COM_ParseError( char *format, ... )
  305. {
  306.     va_list argptr;
  307.     static char string[4096];
  308.  
  309.     va_start (argptr, format);
  310.     vsprintf (string, format, argptr);
  311.     va_end (argptr);
  312.  
  313.     Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string);
  314. }
  315.  
  316. void COM_ParseWarning( char *format, ... )
  317. {
  318.     va_list argptr;
  319.     static char string[4096];
  320.  
  321.     va_start (argptr, format);
  322.     vsprintf (string, format, argptr);
  323.     va_end (argptr);
  324.  
  325.     Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string);
  326. }
  327.  
  328. /*
  329. ==============
  330. COM_Parse
  331.  
  332. Parse a token out of a string
  333. Will never return NULL, just empty strings
  334.  
  335. If "allowLineBreaks" is qtrue then an empty
  336. string will be returned if the next token is
  337. a newline.
  338. ==============
  339. */
  340. const char *SkipWhitespace( const char *data, qboolean *hasNewLines ) {
  341.     int c;
  342.  
  343.     while( (c = *data) <= ' ') {
  344.         if( !c ) {
  345.             return NULL;
  346.         }
  347.         if( c == '\n' ) {
  348.             com_lines++;
  349.             *hasNewLines = qtrue;
  350.         }
  351.         data++;
  352.     }
  353.  
  354.     return data;
  355. }
  356.  
  357. int COM_Compress( char *data_p ) {
  358.     char *in, *out;
  359.     int c;
  360.     qboolean newline = qfalse, whitespace = qfalse;
  361.     
  362.     in = out = data_p;
  363.     if (in) {
  364.         while ((c = *in) != 0) {
  365.             // skip double slash comments
  366.             if ( c == '/' && in[1] == '/' ) {
  367.                 while (*in && *in != '\n') {
  368.                     in++;
  369.                 }
  370.                 // skip /* */ comments
  371.             } else if ( c == '/' && in[1] == '*' ) {
  372.                 while ( *in && ( *in != '*' || in[1] != '/' ) ) 
  373.                     in++;
  374.                 if ( *in ) 
  375.                     in += 2;
  376.                 // record when we hit a newline
  377.             } else if ( c == '\n' || c == '\r' ) {
  378.                 newline = qtrue;
  379.                 in++;
  380.                 // record when we hit whitespace
  381.             } else if ( c == ' ' || c == '\t') {
  382.                 whitespace = qtrue;
  383.                 in++;
  384.                 // an actual token
  385.             } else {
  386.                 // if we have a pending newline, emit it (and it counts as whitespace)
  387.                 if (newline) {
  388.                     *out++ = '\n';
  389.                     newline = qfalse;
  390.                     whitespace = qfalse;
  391.                 } if (whitespace) {
  392.                     *out++ = ' ';
  393.                     whitespace = qfalse;
  394.                 }
  395.                 
  396.                 // copy quoted strings unmolested
  397.                 if (c == '"') {
  398.                     *out++ = c;
  399.                     in++;
  400.                     while (1) {
  401.                         c = *in;
  402.                         if (c && c != '"') {
  403.                             *out++ = c;
  404.                             in++;
  405.                         } else {
  406.                             break;
  407.                         }
  408.                     }
  409.                     if (c == '"') {
  410.                         *out++ = c;
  411.                         in++;
  412.                     }
  413.                 } else {
  414.                     *out = c;
  415.                     out++;
  416.                     in++;
  417.                 }
  418.             }
  419.         }
  420.     }
  421.     *out = 0;
  422.     return out - data_p;
  423. }
  424.  
  425. char *COM_ParseExt( const char **data_p, qboolean allowLineBreaks )
  426. {
  427.     int c = 0, len;
  428.     qboolean hasNewLines = qfalse;
  429.     const char *data;
  430.  
  431.     data = *data_p;
  432.     len = 0;
  433.     com_token[0] = 0;
  434.  
  435.     // make sure incoming data is valid
  436.     if ( !data )
  437.     {
  438.         *data_p = NULL;
  439.         return com_token;
  440.     }
  441.  
  442.     while ( 1 )
  443.     {
  444.         // skip whitespace
  445.         data = SkipWhitespace( data, &hasNewLines );
  446.         if ( !data )
  447.         {
  448.             *data_p = NULL;
  449.             return com_token;
  450.         }
  451.         if ( hasNewLines && !allowLineBreaks )
  452.         {
  453.             *data_p = data;
  454.             return com_token;
  455.         }
  456.  
  457.         c = *data;
  458.  
  459.         // skip double slash comments
  460.         if ( c == '/' && data[1] == '/' )
  461.         {
  462.             data += 2;
  463.             while (*data && *data != '\n') {
  464.                 data++;
  465.             }
  466.         }
  467.         // skip /* */ comments
  468.         else if ( c=='/' && data[1] == '*' ) 
  469.         {
  470.             data += 2;
  471.             while ( *data && ( *data != '*' || data[1] != '/' ) ) 
  472.             {
  473.                 data++;
  474.             }
  475.             if ( *data ) 
  476.             {
  477.                 data += 2;
  478.             }
  479.         }
  480.         else
  481.         {
  482.             break;
  483.         }
  484.     }
  485.  
  486.     // handle quoted strings
  487.     if (c == '\"')
  488.     {
  489.         data++;
  490.         while (1)
  491.         {
  492.             c = *data++;
  493.             if (c=='\"' || !c)
  494.             {
  495.                 com_token[len] = 0;
  496.                 *data_p = ( char * ) data;
  497.                 return com_token;
  498.             }
  499.             if (len < MAX_TOKEN_CHARS)
  500.             {
  501.                 com_token[len] = c;
  502.                 len++;
  503.             }
  504.         }
  505.     }
  506.  
  507.     // parse a regular word
  508.     do
  509.     {
  510.         if (len < MAX_TOKEN_CHARS)
  511.         {
  512.             com_token[len] = c;
  513.             len++;
  514.         }
  515.         data++;
  516.         c = *data;
  517.         if ( c == '\n' )
  518.             com_lines++;
  519.     } while (c>32);
  520.  
  521.     if (len == MAX_TOKEN_CHARS)
  522.     {
  523. //        Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
  524.         len = 0;
  525.     }
  526.     com_token[len] = 0;
  527.  
  528.     *data_p = ( char * ) data;
  529.     return com_token;
  530. }
  531.  
  532.  
  533. #if 0
  534. // no longer used
  535. /*
  536. ===============
  537. COM_ParseInfos
  538. ===============
  539. */
  540. int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {
  541.     char    *token;
  542.     int        count;
  543.     char    key[MAX_TOKEN_CHARS];
  544.  
  545.     count = 0;
  546.  
  547.     while ( 1 ) {
  548.         token = COM_Parse( &buf );
  549.         if ( !token[0] ) {
  550.             break;
  551.         }
  552.         if ( strcmp( token, "{" ) ) {
  553.             Com_Printf( "Missing { in info file\n" );
  554.             break;
  555.         }
  556.  
  557.         if ( count == max ) {
  558.             Com_Printf( "Max infos exceeded\n" );
  559.             break;
  560.         }
  561.  
  562.         infos[count][0] = 0;
  563.         while ( 1 ) {
  564.             token = COM_ParseExt( &buf, qtrue );
  565.             if ( !token[0] ) {
  566.                 Com_Printf( "Unexpected end of info file\n" );
  567.                 break;
  568.             }
  569.             if ( !strcmp( token, "}" ) ) {
  570.                 break;
  571.             }
  572.             Q_strncpyz( key, token, sizeof( key ) );
  573.  
  574.             token = COM_ParseExt( &buf, qfalse );
  575.             if ( !token[0] ) {
  576.                 strcpy( token, "<NULL>" );
  577.             }
  578.             Info_SetValueForKey( infos[count], key, token );
  579.         }
  580.         count++;
  581.     }
  582.  
  583.     return count;
  584. }
  585. #endif
  586.  
  587.  
  588. /*
  589. ==================
  590. COM_MatchToken
  591. ==================
  592. */
  593. void COM_MatchToken( const char **buf_p, char *match ) {
  594.     char    *token;
  595.  
  596.     token = COM_Parse( buf_p );
  597.     if ( strcmp( token, match ) ) {
  598.         Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match );
  599.     }
  600. }
  601.  
  602.  
  603. /*
  604. =================
  605. SkipBracedSection
  606.  
  607. The next token should be an open brace.
  608. Skips until a matching close brace is found.
  609. Internal brace depths are properly skipped.
  610. =================
  611. */
  612. void SkipBracedSection (const char **program) {
  613.     char            *token;
  614.     int                depth;
  615.  
  616.     depth = 0;
  617.     do {
  618.         token = COM_ParseExt( program, qtrue );
  619.         if( token[1] == 0 ) {
  620.             if( token[0] == '{' ) {
  621.                 depth++;
  622.             }
  623.             else if( token[0] == '}' ) {
  624.                 depth--;
  625.             }
  626.         }
  627.     } while( depth && *program );
  628. }
  629.  
  630. /*
  631. =================
  632. SkipRestOfLine
  633. =================
  634. */
  635. void SkipRestOfLine ( const char **data ) {
  636.     const char    *p;
  637.     int        c;
  638.  
  639.     p = *data;
  640.     while ( (c = *p++) != 0 ) {
  641.         if ( c == '\n' ) {
  642.             com_lines++;
  643.             break;
  644.         }
  645.     }
  646.  
  647.     *data = p;
  648. }
  649.  
  650.  
  651. void Parse1DMatrix (const char **buf_p, int x, float *m) {
  652.     char    *token;
  653.     int        i;
  654.  
  655.     COM_MatchToken( buf_p, "(" );
  656.  
  657.     for (i = 0 ; i < x ; i++) {
  658.         token = COM_Parse(buf_p);
  659.         m[i] = atof(token);
  660.     }
  661.  
  662.     COM_MatchToken( buf_p, ")" );
  663. }
  664.  
  665. void Parse2DMatrix (const char **buf_p, int y, int x, float *m) {
  666.     int        i;
  667.  
  668.     COM_MatchToken( buf_p, "(" );
  669.  
  670.     for (i = 0 ; i < y ; i++) {
  671.         Parse1DMatrix (buf_p, x, m + i * x);
  672.     }
  673.  
  674.     COM_MatchToken( buf_p, ")" );
  675. }
  676.  
  677. void Parse3DMatrix (const char **buf_p, int z, int y, int x, float *m) {
  678.     int        i;
  679.  
  680.     COM_MatchToken( buf_p, "(" );
  681.  
  682.     for (i = 0 ; i < z ; i++) {
  683.         Parse2DMatrix (buf_p, y, x, m + i * x*y);
  684.     }
  685.  
  686.     COM_MatchToken( buf_p, ")" );
  687. }
  688.  
  689.  
  690. /*
  691. ============================================================================
  692.  
  693.                     LIBRARY REPLACEMENT FUNCTIONS
  694.  
  695. ============================================================================
  696. */
  697.  
  698. int Q_isprint( int c )
  699. {
  700.     if ( c >= 0x20 && c <= 0x7E )
  701.         return ( 1 );
  702.     return ( 0 );
  703. }
  704.  
  705. int Q_islower( int c )
  706. {
  707.     if (c >= 'a' && c <= 'z')
  708.         return ( 1 );
  709.     return ( 0 );
  710. }
  711.  
  712. int Q_isupper( int c )
  713. {
  714.     if (c >= 'A' && c <= 'Z')
  715.         return ( 1 );
  716.     return ( 0 );
  717. }
  718.  
  719. int Q_isalpha( int c )
  720. {
  721.     if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
  722.         return ( 1 );
  723.     return ( 0 );
  724. }
  725.  
  726. char* Q_strrchr( const char* string, int c )
  727. {
  728.     char cc = c;
  729.     char *s;
  730.     char *sp=(char *)0;
  731.  
  732.     s = (char*)string;
  733.  
  734.     while (*s)
  735.     {
  736.         if (*s == cc)
  737.             sp = s;
  738.         s++;
  739.     }
  740.     if (cc == 0)
  741.         sp = s;
  742.  
  743.     return sp;
  744. }
  745.  
  746. /*
  747. =============
  748. Q_strncpyz
  749.  
  750. Safe strncpy that ensures a trailing zero
  751. =============
  752. */
  753. void Q_strncpyz( char *dest, const char *src, int destsize ) 
  754. {    // bk001129 - also NULL dest
  755.     if ( !dest ) 
  756.     {
  757.         Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
  758.     }
  759.     if ( !src ) 
  760.     {
  761.         Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
  762.     }
  763.     if ( destsize < 1 ) 
  764.     {
  765.         Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); 
  766.     }
  767.  
  768.     strncpy( dest, src, destsize-1 );
  769.     dest[destsize-1] = 0;
  770. }
  771.                  
  772. int Q_stricmpn (const char *s1, const char *s2, int n) {
  773.     int        c1, c2;
  774.  
  775.     // bk001129 - moved in 1.17 fix not in id codebase
  776.         if ( s1 == NULL ) {
  777.            if ( s2 == NULL )
  778.              return 0;
  779.            else
  780.              return -1;
  781.         }
  782.         else if ( s2==NULL )
  783.           return 1;
  784.  
  785.  
  786.     
  787.     do {
  788.         c1 = *s1++;
  789.         c2 = *s2++;
  790.  
  791.         if (!n--) {
  792.             return 0;        // strings are equal until end point
  793.         }
  794.         
  795.         if (c1 != c2) {
  796.             if (c1 >= 'a' && c1 <= 'z') {
  797.                 c1 -= ('a' - 'A');
  798.             }
  799.             if (c2 >= 'a' && c2 <= 'z') {
  800.                 c2 -= ('a' - 'A');
  801.             }
  802.             if (c1 != c2) {
  803.                 return c1 < c2 ? -1 : 1;
  804.             }
  805.         }
  806.     } while (c1);
  807.     
  808.     return 0;        // strings are equal
  809. }
  810.  
  811. int Q_strncmp (const char *s1, const char *s2, int n) {
  812.     int        c1, c2;
  813.     
  814.     do {
  815.         c1 = *s1++;
  816.         c2 = *s2++;
  817.  
  818.         if (!n--) {
  819.             return 0;        // strings are equal until end point
  820.         }
  821.         
  822.         if (c1 != c2) {
  823.             return c1 < c2 ? -1 : 1;
  824.         }
  825.     } while (c1);
  826.     
  827.     return 0;        // strings are equal
  828. }
  829.  
  830. int Q_stricmp (const char *s1, const char *s2) {
  831.     return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
  832. }
  833.  
  834.  
  835. char *Q_strlwr( char *s1 ) {
  836.     char    *s;
  837.  
  838.     s = s1;
  839.     while ( *s ) {
  840.         *s = tolower(*s);
  841.         s++;
  842.     }
  843.     return s1;
  844. }
  845.  
  846. char *Q_strupr( char *s1 ) {
  847.     char    *s;
  848.  
  849.     s = s1;
  850.     while ( *s ) {
  851.         *s = toupper(*s);
  852.         s++;
  853.     }
  854.     return s1;
  855. }
  856.  
  857.  
  858. // never goes past bounds or leaves without a terminating 0
  859. void Q_strcat( char *dest, int size, const char *src ) {
  860.     int        l1;
  861.  
  862.     l1 = strlen( dest );
  863.     if ( l1 >= size ) {
  864.         Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
  865.     }
  866.     Q_strncpyz( dest + l1, src, size - l1 );
  867. }
  868.  
  869.  
  870. int Q_PrintStrlen( const char *string ) {
  871.     int            len;
  872.     const char    *p;
  873.  
  874.     if( !string ) {
  875.         return 0;
  876.     }
  877.  
  878.     len = 0;
  879.     p = string;
  880.     while( *p ) 
  881.     {
  882.         if( *p == '^' ) 
  883.         {
  884.             p++;
  885.             if ( *p != '^' )
  886.             {
  887.                 p ++;
  888.                 continue;
  889.             }
  890.         }
  891.         p++;
  892.         len++;
  893.     }
  894.  
  895.     return len;
  896. }
  897.  
  898.  
  899. char *Q_CleanStr( char *string ) {
  900.     char*    d;
  901.     char*    s;
  902.     int        c;
  903.  
  904.     s = string;
  905.     d = string;
  906.     while ((c = *s) != 0 ) {
  907.  
  908.         if( *s == '^' ) 
  909.         {
  910.             s++;
  911.             if( *s == '^' ) 
  912.             {
  913.                 *d++ = '^';
  914.                 *d++ = '^';
  915.             }
  916.         }
  917.         else if ( c >= 0x20 && c <= 0x7E ) 
  918.         {
  919.             *d++ = c;
  920.         }
  921.         s++;
  922.     }
  923.     *d = '\0';
  924.  
  925.     return string;
  926. }
  927.  
  928.  
  929. int QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) 
  930. {
  931.     int        len;
  932.     va_list    argptr;
  933.     char    bigbuffer[32000];    // big, but small enough to fit in PPC stack
  934.  
  935.     va_start (argptr,fmt);
  936.     len = vsprintf (bigbuffer,fmt,argptr) + 1;
  937.     va_end (argptr);
  938.     if ( len >= sizeof( bigbuffer ) ) {
  939.         Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
  940.     }
  941.     if (len >= size) {
  942.         Com_Printf ("Com_sprintf: overflow of %i in %i for '%s'\n", len, size, fmt);
  943. #ifdef    _DEBUG
  944.         __asm {
  945.             int 3;
  946.         }
  947. #endif
  948.     }
  949.     Q_strncpyz (dest, bigbuffer, len );
  950.  
  951.     return len-1;
  952. }
  953.  
  954.  
  955. /*
  956. ============
  957. va
  958.  
  959. does a varargs printf into a temp buffer, so I don't need to have
  960. varargs versions of all text functions.
  961. FIXME: make this buffer size safe someday
  962. ============
  963. */
  964. char    * QDECL va( char *format, ... ) {
  965.     va_list        argptr;
  966.     static char        string[2][32000];    // in case va is called by nested functions
  967.     static int        index = 0;
  968.     char    *buf;
  969.  
  970.     buf = string[index & 1];
  971.     index++;
  972.  
  973.     va_start (argptr, format);
  974.     vsprintf (buf, format,argptr);
  975.     va_end (argptr);
  976.  
  977.     return buf;
  978. }
  979.  
  980.  
  981. /*
  982. =====================================================================
  983.  
  984.   INFO STRINGS
  985.  
  986. =====================================================================
  987. */
  988.  
  989. /*
  990. ===============
  991. Info_ValueForKey
  992.  
  993. Searches the string for the given
  994. key and returns the associated value, or an empty string.
  995. FIXME: overflow check?
  996. ===============
  997. */
  998. char *Info_ValueForKey( const char *s, const char *key ) {
  999.     char    pkey[BIG_INFO_KEY];
  1000.     static    char value[2][BIG_INFO_VALUE];    // use two buffers so compares
  1001.                                             // work without stomping on each other
  1002.     static    int    valueindex = 0;
  1003.     char    *o;
  1004.     
  1005.     if ( !s || !key ) {
  1006.         return "";
  1007.     }
  1008.  
  1009.     if ( strlen( s ) >= BIG_INFO_STRING ) {
  1010.         Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
  1011.     }
  1012.  
  1013.     valueindex ^= 1;
  1014.     if (*s == '\\')
  1015.         s++;
  1016.     while (1)
  1017.     {
  1018.         o = pkey;
  1019.         while (*s != '\\')
  1020.         {
  1021.             if (!*s)
  1022.                 return "";
  1023.             *o++ = *s++;
  1024.         }
  1025.         *o = 0;
  1026.         s++;
  1027.  
  1028.         o = value[valueindex];
  1029.  
  1030.         while (*s != '\\' && *s)
  1031.         {
  1032.             *o++ = *s++;
  1033.         }
  1034.         *o = 0;
  1035.  
  1036.         if (!Q_stricmp (key, pkey) )
  1037.             return value[valueindex];
  1038.  
  1039.         if (!*s)
  1040.             break;
  1041.         s++;
  1042.     }
  1043.  
  1044.     return "";
  1045. }
  1046.  
  1047.  
  1048. /*
  1049. ===================
  1050. Info_NextPair
  1051.  
  1052. Used to itterate through all the key/value pairs in an info string
  1053. ===================
  1054. */
  1055. void Info_NextPair( const char **head, char *key, char *value ) {
  1056.     char    *o;
  1057.     const char    *s;
  1058.  
  1059.     s = *head;
  1060.  
  1061.     if ( *s == '\\' ) {
  1062.         s++;
  1063.     }
  1064.     key[0] = 0;
  1065.     value[0] = 0;
  1066.  
  1067.     o = key;
  1068.     while ( *s != '\\' ) {
  1069.         if ( !*s ) {
  1070.             *o = 0;
  1071.             *head = s;
  1072.             return;
  1073.         }
  1074.         *o++ = *s++;
  1075.     }
  1076.     *o = 0;
  1077.     s++;
  1078.  
  1079.     o = value;
  1080.     while ( *s != '\\' && *s ) {
  1081.         *o++ = *s++;
  1082.     }
  1083.     *o = 0;
  1084.  
  1085.     *head = s;
  1086. }
  1087.  
  1088.  
  1089. /*
  1090. ===================
  1091. Info_RemoveKey
  1092. ===================
  1093. */
  1094. void Info_RemoveKey( char *s, const char *key ) {
  1095.     char    *start;
  1096.     char    pkey[MAX_INFO_KEY];
  1097.     char    value[MAX_INFO_VALUE];
  1098.     char    *o;
  1099.  
  1100.     if ( strlen( s ) >= MAX_INFO_STRING ) {
  1101.         Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
  1102.     }
  1103.  
  1104.     if (strchr (key, '\\')) {
  1105.         return;
  1106.     }
  1107.  
  1108.     while (1)
  1109.     {
  1110.         start = s;
  1111.         if (*s == '\\')
  1112.             s++;
  1113.         o = pkey;
  1114.         while (*s != '\\')
  1115.         {
  1116.             if (!*s)
  1117.                 return;
  1118.             *o++ = *s++;
  1119.         }
  1120.         *o = 0;
  1121.         s++;
  1122.  
  1123.         o = value;
  1124.         while (*s != '\\' && *s)
  1125.         {
  1126.             if (!*s)
  1127.                 return;
  1128.             *o++ = *s++;
  1129.         }
  1130.         *o = 0;
  1131.  
  1132.         if (!strcmp (key, pkey) )
  1133.         {
  1134.             strcpy (start, s);    // remove this part
  1135.             return;
  1136.         }
  1137.  
  1138.         if (!*s)
  1139.             return;
  1140.     }
  1141.  
  1142. }
  1143.  
  1144. /*
  1145. ===================
  1146. Info_RemoveKey_Big
  1147. ===================
  1148. */
  1149. void Info_RemoveKey_Big( char *s, const char *key ) {
  1150.     char    *start;
  1151.     char    pkey[BIG_INFO_KEY];
  1152.     char    value[BIG_INFO_VALUE];
  1153.     char    *o;
  1154.  
  1155.     if ( strlen( s ) >= BIG_INFO_STRING ) {
  1156.         Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" );
  1157.     }
  1158.  
  1159.     if (strchr (key, '\\')) {
  1160.         return;
  1161.     }
  1162.  
  1163.     while (1)
  1164.     {
  1165.         start = s;
  1166.         if (*s == '\\')
  1167.             s++;
  1168.         o = pkey;
  1169.         while (*s != '\\')
  1170.         {
  1171.             if (!*s)
  1172.                 return;
  1173.             *o++ = *s++;
  1174.         }
  1175.         *o = 0;
  1176.         s++;
  1177.  
  1178.         o = value;
  1179.         while (*s != '\\' && *s)
  1180.         {
  1181.             if (!*s)
  1182.                 return;
  1183.             *o++ = *s++;
  1184.         }
  1185.         *o = 0;
  1186.  
  1187.         if (!strcmp (key, pkey) )
  1188.         {
  1189.             strcpy (start, s);    // remove this part
  1190.             return;
  1191.         }
  1192.  
  1193.         if (!*s)
  1194.             return;
  1195.     }
  1196.  
  1197. }
  1198.  
  1199.  
  1200.  
  1201.  
  1202. /*
  1203. ==================
  1204. Info_Validate
  1205.  
  1206. Some characters are illegal in info strings because they
  1207. can mess up the server's parsing
  1208. ==================
  1209. */
  1210. qboolean Info_Validate( const char *s ) {
  1211.     if ( strchr( s, '\"' ) ) {
  1212.         return qfalse;
  1213.     }
  1214.     if ( strchr( s, ';' ) ) {
  1215.         return qfalse;
  1216.     }
  1217.     return qtrue;
  1218. }
  1219.  
  1220. /*
  1221. ==================
  1222. Info_SetValueForKey
  1223.  
  1224. Changes or adds a key/value pair
  1225. ==================
  1226. */
  1227. void Info_SetValueForKey( char *s, const char *key, const char *value ) {
  1228.     char    newi[MAX_INFO_STRING];
  1229.  
  1230.     if ( strlen( s ) >= MAX_INFO_STRING ) {
  1231.         Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
  1232.     }
  1233.  
  1234.     if (strchr (key, '\\') || strchr (value, '\\'))
  1235.     {
  1236.         Com_Printf ("Can't use keys or values with a \\\n");
  1237.         return;
  1238.     }
  1239.  
  1240.     if (strchr (key, ';') || strchr (value, ';'))
  1241.     {
  1242.         Com_Printf ("Can't use keys or values with a semicolon\n");
  1243.         return;
  1244.     }
  1245.  
  1246.     if (strchr (key, '\"') || strchr (value, '\"'))
  1247.     {
  1248.         Com_Printf ("Can't use keys or values with a \"\n");
  1249.         return;
  1250.     }
  1251.  
  1252.     Info_RemoveKey (s, key);
  1253.     if (!value || !strlen(value))
  1254.         return;
  1255.  
  1256.     Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
  1257.  
  1258.     if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
  1259.     {
  1260.         Com_Printf ("Info string length exceeded\n");
  1261.         return;
  1262.     }
  1263.  
  1264.     strcat (newi, s);
  1265.     strcpy (s, newi);
  1266. }
  1267.  
  1268. /*
  1269. ==================
  1270. Info_SetValueForKey_Big
  1271.  
  1272. Changes or adds a key/value pair
  1273. ==================
  1274. */
  1275. void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
  1276.     char    newi[BIG_INFO_STRING];
  1277.  
  1278.     if ( strlen( s ) >= BIG_INFO_STRING ) {
  1279.         Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
  1280.     }
  1281.  
  1282.     if (strchr (key, '\\') || strchr (value, '\\'))
  1283.     {
  1284.         Com_Printf ("Can't use keys or values with a \\\n");
  1285.         return;
  1286.     }
  1287.  
  1288.     if (strchr (key, ';') || strchr (value, ';'))
  1289.     {
  1290.         Com_Printf ("Can't use keys or values with a semicolon\n");
  1291.         return;
  1292.     }
  1293.  
  1294.     if (strchr (key, '\"') || strchr (value, '\"'))
  1295.     {
  1296.         Com_Printf ("Can't use keys or values with a \"\n");
  1297.         return;
  1298.     }
  1299.  
  1300.     Info_RemoveKey_Big (s, key);
  1301.     if (!value || !strlen(value))
  1302.         return;
  1303.  
  1304.     Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
  1305.  
  1306.     if (strlen(newi) + strlen(s) > BIG_INFO_STRING)
  1307.     {
  1308.         Com_Printf ("BIG Info string length exceeded\n");
  1309.         return;
  1310.     }
  1311.  
  1312.     strcat (s, newi);
  1313. }
  1314.  
  1315.  
  1316. //rww - convience function..
  1317. int Q_irand(int value1, int value2)
  1318. {
  1319.     int r;
  1320.  
  1321.     r = rand()%value2;
  1322.     r += value1;
  1323.     
  1324.     return r;
  1325. }
  1326.  
  1327. //====================================================================
  1328. // Generic Keyword hash
  1329. //====================================================================
  1330. int KeywordHash_Key ( char *keyword ) 
  1331. {
  1332.     int register hash, i;
  1333.  
  1334.     hash = 0;
  1335.     for (i = 0; keyword[i] != '\0'; i++) 
  1336.     {
  1337.         if (keyword[i] >= 'A' && keyword[i] <= 'Z')
  1338.             hash += (keyword[i] + ('a' - 'A')) * (119 + i);
  1339.         else
  1340.             hash += keyword[i] * (119 + i);
  1341.     }
  1342.  
  1343.     hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1);
  1344.  
  1345.     return hash;
  1346. }
  1347.  
  1348. void KeywordHash_Add( keywordHash_t *table[], keywordHash_t *key ) 
  1349. {
  1350.     int hash;
  1351.  
  1352.     hash = KeywordHash_Key ( key->name );
  1353.  
  1354. /*
  1355.     if (table[hash]) 
  1356.     {
  1357.         int collision = qtrue;
  1358.     }
  1359. */
  1360.     key->next = table[hash];
  1361.     table[hash] = key;
  1362. }
  1363.  
  1364. keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
  1365. {
  1366.     keywordHash_t *key;
  1367.     int hash;
  1368.  
  1369.     hash = KeywordHash_Key(keyword);
  1370.     for (key = table[hash]; key; key = key->next)
  1371.     {
  1372.         if (!Q_stricmp(key->name, keyword))
  1373.         {
  1374.             return key;
  1375.         }
  1376.     }
  1377.  
  1378.     return NULL;
  1379. }
  1380.  
  1381.